package juc.executors;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class ExecutorExample1 {

    public static void main(String[] args) {
        //useCachedThreadPool();
        //useFixedSizePool();
        useSinglePool();
    }

    /**
     * SingleThreadExecutor different between one Thread.
     * Thread will die after finish work,but SingleThreadExecutor can always alive.
     * Thread can not put the submitted runnable to the cache queue but SingleThreadExecutor can do this.
     *
     * return new FinalizableDelegatedExecutorService
     *             (new ThreadPoolExecutor(1, 1,
     *                                      0L, TimeUnit.MILLISECONDS,
     *                                     new LinkedBlockingQueue<Runnable>()));
     * 等价于Executors.newFixedThreadPool(1);
     * 为什么用FinalizableDelegatedExecutorService包装呢？
     * FinalizableDelegatedExecutorService extends DelegatedExecutorService
     * A wrapper class that exposes only the ExecutorService methods of an ExecutorService implementation.
     * 只暴露ExecutorService的方法
     * 事情是ThreadPoolExecutor做的，但ThreadPoolExecutor的方法不能被调用
     *
     * 始终只有一个线程，执行完不会销毁
     */
    private static void useSinglePool(){
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        IntStream.range(0, 10).boxed().forEach(i -> executorService.execute(() -> {
            timeSleep(2);
            System.out.println(Thread.currentThread().getName() + " [" + i + "]");
        }));
        timeSleep(1);
        //这个转换会失败，因用FinalizableDelegatedExecutorService包装
        //System.out.println(((ThreadPoolExecutor) executorService).getActiveCount());
    }

    private static void useFixedSizePool() {
        /**
         * return new ThreadPoolExecutor(nThreads, nThreads,
         *                                       0L, TimeUnit.MILLISECONDS,
         *                                       new LinkedBlockingQueue<Runnable>());
         *  初始线程数和最大线程数相等，所以超时时间没有意义是0L，执行完不会销毁
         *  LinkedBlockingQueue可以放Integer.MAX_VALUE个
         */
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        IntStream.range(0, 10).boxed().forEach(i -> executorService.execute(() -> {
            timeSleep(2);
            System.out.println(Thread.currentThread().getName() + " [" + i + "]");
        }));
        timeSleep(1);
        System.out.println(((ThreadPoolExecutor) executorService).getActiveCount());
    }

    /**
     * These pools will typically improve the performance
     * of programs that execute many short-lived asynchronous tasks.
     * <p/>
     */
    private static void useCachedThreadPool() {
        /**
         * return new ThreadPoolExecutor(0,Integer.MAX_VALUE,
         *                                  60L,TimeUnit.SECONDS,
         *                                  new SynchronousQueue<Runnable>());
         * 初始是0个，会一个一个创建，执行完会销毁
         * 这里的SynchronousQueue一次只能放一个元素
         */
        ExecutorService executorService = Executors.newCachedThreadPool();
        System.out.println(((ThreadPoolExecutor) executorService).getActiveCount());

        executorService.execute(() -> {
            System.out.println("===");
        });
        System.out.println(((ThreadPoolExecutor) executorService).getActiveCount());

        IntStream.range(0, 100).boxed().forEach(i -> executorService.execute(() -> {
            timeSleep(2);
            System.out.println(Thread.currentThread().getName() + " [" + i + "]");
        }));
        timeSleep(1);
        System.out.println(((ThreadPoolExecutor) executorService).getActiveCount());

    }

    private static void timeSleep(long time) {
        try {
            TimeUnit.SECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
